package com.qiaofang.applet.service.member.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.qiaofang.applet.common.base.MongoBaseService;
import com.qiaofang.applet.common.context.QfContextHolder;
import com.qiaofang.applet.common.exception.BusinessException;
import com.qiaofang.applet.constants.BusinessConstants;
import com.qiaofang.applet.constants.DailyDataTypeConstants;
import com.qiaofang.applet.constants.MemberOperateTypeConstants;
import com.qiaofang.applet.service.member.domain.*;
import com.qiaofang.applet.service.member.repository.EmployeeRepository;
import com.qiaofang.applet.service.member.repository.MemberFocusRepository;
import com.qiaofang.applet.service.member.repository.MemberOperateRepository;
import com.qiaofang.applet.service.member.repository.MemberRepository;
import com.qiaofang.applet.service.member.service.*;
import com.qiaofang.applet.service.member.service.dto.*;
import com.qiaofang.applet.service.member.service.mapstruct.MemberOperateMapper;
import com.qiaofang.applet.service.other.service.CityCompanyService;
import com.qiaofang.applet.service.other.util.DateTypeUtil;
import com.qiaofang.applet.service.property.domain.FirsthandEstate;
import com.qiaofang.applet.service.property.domain.Property;
import com.qiaofang.applet.service.property.repository.PropertyRepository;
import com.qiaofang.applet.service.property.service.FirsthandEstateService;
import com.qiaofang.applet.service.property.service.dto.FirsthandEstateListDto;
import com.qiaofang.applet.service.property.service.dto.FirsthandEstateQueryDto;
import com.qiaofang.applet.service.property.service.dto.MyPropertyListDto;
import com.qiaofang.applet.service.property.service.dto.VisitorRecordsSimpleDto;
import com.qiaofang.applet.service.property.service.mapstruct.FirsthandEstateMapper;
import com.qiaofang.applet.service.property.service.mapstruct.PropertyMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;

import static org.springframework.data.domain.Sort.Direction.DESC;

/**
 * @author daiyuxiang
 */
@Slf4j
@Service
public class MemberOperateServiceImpl extends MongoBaseService<MemberOperate, String> implements MemberOperateService {


    private final MemberOperateRepository repository;

    @Autowired
    public MemberOperateServiceImpl(MemberOperateRepository repository) {
        super(repository);
        this.repository = repository;
    }

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private MemberRepository memberRepository;

    @Autowired
    private MemberOperateMapper memberOperateMapper;

    @Autowired
    private FirsthandEstateService firsthandEstateService;

    @Autowired
    private MemberExploreService memberExploreService;

    @Autowired
    private PropertyRepository propertyRepository;

    @Autowired
    private FirsthandEstateMapper firsthandEstateMapper;

    @Autowired
    private PropertyMapper propertyMapper;

    @Autowired
    private EmployeeRepository employeeRepository;

    @Autowired
    private EmployeeService employeeService;

    @Autowired
    private EmployeePropertyService employeePropertyService;

    @Autowired
    private MemberFocusRepository memberFocusRepository;

    @Autowired
    private CityCompanyService cityCompanyService;

    @Autowired
    private DepartmentService departmentService;


    @Override
    public FollowersAndVisitorsDto getIndexFollowersAndVisitors(String uniqueUuid, String memberId) {

        FollowersAndVisitorsDto followersAndVisitorsDto = new FollowersAndVisitorsDto();

        String corporationCode = QfContextHolder.getContext().getCorporationCode();

        Criteria criteria = new Criteria();
        criteria.and("corporationCode").is(corporationCode);
        criteria.and("operateType").is(MemberOperateTypeConstants.EXPLORE.getValue());
        criteria.and("employeeUniqueUuid").is(uniqueUuid);
        criteria.and("memberId").ne(memberId);
        criteria.and("createTime").gte(DateTypeUtil.getBeginOrAfterDay(new Date(), Calendar.DAY_OF_MONTH, -30));
        Query query = new Query(criteria);

        List<String> visitList = mongoTemplate.findDistinct(query, "memberId", MemberOperate.class, String.class);
        //30天访客
        followersAndVisitorsDto.setMonthOfVisitors(CollectionUtils.isEmpty(visitList) ? 0 : visitList.size());
        //经纪人会员信息
        Member member = memberRepository.findFirstByCorporationCodeAndEmployeeUniqueUuid(corporationCode, uniqueUuid);
        log.info("经纪人会员数据：{}", JSONObject.toJSONString(member));
        if (member == null) {
            followersAndVisitorsDto.setAttention(0);
            log.info("该经纪人:{} 暂无关注", uniqueUuid);
        } else {
            Criteria criteriaAttention = new Criteria();
            criteriaAttention.and("corporationCode").is(corporationCode);
            criteriaAttention.and("businessType").is(BusinessConstants.MEMBER.getValue());
            criteriaAttention.and("memberId").is(member.getId());
            Query queryAttention = new Query(criteriaAttention);
            long attentionCount = mongoTemplate.count(queryAttention, MemberFocus.class);
            followersAndVisitorsDto.setAttention((int) attentionCount);
            log.info("该经纪人:{} 关注数：{}", uniqueUuid, attentionCount);
        }
        //粉丝
        Criteria criteriaFans = new Criteria();
        criteriaFans.and("corporationCode").is(corporationCode);
        criteriaFans.and("businessType").is(BusinessConstants.EMPLOYEE.getValue());
        criteriaFans.and("businessUuid").is(uniqueUuid);
        Query queryFans = new Query(criteriaFans);
        long fansCount = mongoTemplate.count(queryFans, MemberFocus.class);
        followersAndVisitorsDto.setFans((int) fansCount);
        log.info("该经纪人:{} 粉丝数：{}", uniqueUuid, fansCount);

        //经纪人名片数据
        Employee employee = employeeService.findByEmployeeUniqueUuid(uniqueUuid);
        log.info("我是经纪人首页，经纪人数据:{}", JSONObject.toJSONString(employee));
        EmployeeListDto employeeListDto = employeeService.domainToListDto(employee);
        if (employeeListDto != null) {
            followersAndVisitorsDto.setEmployeeName(employeeListDto.getEmployeeName());
            followersAndVisitorsDto.setDeptName(employeeListDto.getDeptName());
            followersAndVisitorsDto.setEmployeePhotoUrl(employeeListDto.getEmployeePhotoUrl());
        }

        //经纪人门店房源数据
        EmployeeHouseNumDto employeeHouseNum = employeePropertyService.getEmployeeHouseNum(uniqueUuid);
        log.info("经纪人首页，门店房源数据:{}", JSONObject.toJSONString(employeeHouseNum));
        BeanUtils.copyProperties(employeeHouseNum, followersAndVisitorsDto);
        return followersAndVisitorsDto;
    }

    @Override
    public DailyDataDto getDailyData(DailyDataQueryDto dailyDataQueryDto) {

        DailyDataDto dailyDataDto = new DailyDataDto();
        //默认查询今日访问
        if (StringUtils.equals(dailyDataQueryDto.getType(), DailyDataTypeConstants.VISIT.getDailyDataType())) {
            TodayVisitDto todayVisit = getTodayVisit(dailyDataQueryDto.getEmployeeUniqueUuid(), dailyDataQueryDto.getMemberId());
            BeanUtils.copyProperties(todayVisit, dailyDataDto);
        } else if (StringUtils.equals(dailyDataQueryDto.getType(), DailyDataTypeConstants.FORWARD.getDailyDataType())) {
            TodayForwardDto todayForward = getTodayForward(dailyDataQueryDto.getEmployeeUniqueUuid(), dailyDataQueryDto.getMemberId());
            BeanUtils.copyProperties(todayForward, dailyDataDto);
        } else if (StringUtils.equals(dailyDataQueryDto.getType(), DailyDataTypeConstants.EXCHANGE.getDailyDataType())) {
            TodayExchangeDto todayExchange = getTodayExchange(dailyDataQueryDto.getEmployeeUniqueUuid(), dailyDataQueryDto.getMemberId());
            BeanUtils.copyProperties(todayExchange, dailyDataDto);
        }
        return dailyDataDto;
    }

    @Override
    public TodayVisitDto getTodayVisit(String employeeUniqueUuid, String memberId) {

        String corporationCode = QfContextHolder.getContext().getCorporationCode();

        TodayVisitDto todayVisitDto = new TodayVisitDto();
        //今日时间
        Date dayZero = getDayZero(new Date());
        //今日总访问人数 要以memberid分组
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("corporationCode").is(corporationCode);
        criteria.and("operateType").is(MemberOperateTypeConstants.EXPLORE.getValue());
        criteria.and("employeeUniqueUuid").is(employeeUniqueUuid);
        criteria.and("memberId").ne(memberId);
        criteria.and("createTime").gte(dayZero);
        query.addCriteria(criteria);
        List<String> visitList = mongoTemplate.findDistinct(query, "memberId", MemberOperate.class, String.class);
        if (CollectionUtils.isEmpty(visitList)) {
            todayVisitDto.setVisitorsNum(0);
            todayVisitDto.setTurnFansNum(0);
            todayVisitDto.setAttentionNum(0);
            todayVisitDto.setExchangeNum(0);
            return todayVisitDto;
        }
        todayVisitDto.setVisitorsNum(visitList.size());
        todayVisitDto.setVisitMemberOperateList(visitList);
        log.info("该员工:{} 今日访问总数:{}", employeeUniqueUuid, todayVisitDto.getVisitorsNum());

        //转粉人数
        Query queryFans = new Query();
        Criteria criteriaFans = new Criteria();
        criteriaFans.and("corporationCode").is(corporationCode);
        criteriaFans.and("businessUuid").is(employeeUniqueUuid);
        criteriaFans.and("businessType").is(BusinessConstants.EMPLOYEE.getValue());
        criteriaFans.and("createTime").gte(dayZero);
        queryFans.addCriteria(criteriaFans);
        List<MemberFocus> fansList = Optional.ofNullable(mongoTemplate.find(queryFans, MemberFocus.class)).orElseGet(Lists::newArrayList)
                .stream().filter(f -> visitList.contains(f.getMemberId())).collect(Collectors.toList());
        todayVisitDto.setTurnFansNum(CollectionUtils.isEmpty(fansList) ? 0 : fansList.size());
        todayVisitDto.setFansMemberOperateList(fansList);
        log.info("该员工:{} 今日转粉总数:{}", employeeUniqueUuid, todayVisitDto.getTurnFansNum());

        //关注人数
        Query queryAttention = new Query();
        Criteria criteriaAttention = new Criteria();
        criteriaAttention.and("corporationCode").is(corporationCode);
        criteriaAttention.and("memberId").is(memberId);
        criteriaAttention.and("businessType").is(BusinessConstants.MEMBER.getValue());
        criteriaAttention.and("createTime").gte(dayZero);
        queryAttention.addCriteria(criteriaAttention);

        //我关注人数会员(此接口只在经纪人个人页面操作，故被关注的还是以会员的身份被关注)
        List<MemberFocus> memberIdList = Optional.ofNullable(mongoTemplate.find(queryAttention, MemberFocus.class)).orElseGet(Lists::newArrayList)
                .stream().collect(Collectors.toList());
        List<MemberFocus> attentionList = memberIdList.stream().filter(f -> visitList.contains(f.getBusinessUuid())).collect(Collectors.toList());
        todayVisitDto.setAttentionNum(CollectionUtils.isEmpty(attentionList) ? 0 : attentionList.size());
        todayVisitDto.setAttentionMemberOperateList(attentionList);
        log.info("该员工:{} 今日关注总数:{}", employeeUniqueUuid, todayVisitDto.getAttentionNum());

        //互动人数
        Query queryExchange = new Query();
        Criteria criteriaExchange = new Criteria();
        criteriaExchange.and("corporationCode").is(corporationCode);
        criteriaExchange.and("employeeUniqueUuid").is(employeeUniqueUuid);
        criteriaExchange.and("createTime").gte(dayZero);
        //浏览也算互动
        queryExchange.addCriteria(criteriaExchange);
        List<String> exchangeList = mongoTemplate.findDistinct(queryExchange, "memberId", MemberOperate.class, String.class);
        List<String> exchangeFilterList = Optional.ofNullable(exchangeList).orElseGet(Lists::newArrayList)
                .stream().filter(f -> visitList.contains(f)).collect(Collectors.toList());
        todayVisitDto.setExchangeNum(CollectionUtils.isEmpty(exchangeFilterList) ? 0 : exchangeFilterList.size());
        todayVisitDto.setExchangeMemberOperateList(exchangeFilterList);
        log.info("该员工:{} 今日互动总数:{}", employeeUniqueUuid, todayVisitDto.getExchangeNum());
        return todayVisitDto;
    }

    @Override
    public TodayForwardDto getTodayForward(String employeeUniqueUuid, String memberId) {
        TodayForwardDto todayForwardDto = new TodayForwardDto();
        //今日时间
        Date dayZero = getDayZero(new Date());
        //我分享
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("corporationCode").is(QfContextHolder.getContext().getCorporationCode());
        criteria.and("operateType").is(MemberOperateTypeConstants.SHARE.getValue());
        criteria.and("memberId").is(memberId);
        criteria.and("employeeUniqueUuid").is(employeeUniqueUuid);
        //criteria.and("level").is(0);
        criteria.and("createTime").gte(dayZero);
        query.addCriteria(criteria);
        List<MemberOperate> memberOperates = mongoTemplate.find(query, MemberOperate.class);
        todayForwardDto.setMineForwardNum(CollectionUtils.isEmpty(memberOperates) ? 0 : memberOperates.size());
        todayForwardDto.setMineForwardList(memberOperates);
        log.info("该员工:{} 今日自己分享:{}", employeeUniqueUuid, todayForwardDto.getMineForwardNum());

        //客户分享
        Query queryShare = new Query();
        Criteria criteriaShare = new Criteria();
        criteriaShare.and("corporationCode").is(QfContextHolder.getContext().getCorporationCode());
        criteriaShare.and("operateType").is(MemberOperateTypeConstants.SHARE.getValue());
        criteriaShare.and("memberId").ne(memberId);
        //criteriaShare.and("level").lte(1);
        criteriaShare.and("employeeUniqueUuid").is(employeeUniqueUuid);
        criteriaShare.and("createTime").gte(dayZero);
        queryShare.addCriteria(criteriaShare);
        List<MemberOperate> clientList = mongoTemplate.find(queryShare, MemberOperate.class);
        todayForwardDto.setClientForwardNum(CollectionUtils.isEmpty(clientList) ? 0 : clientList.size());
        todayForwardDto.setClientForwardList(clientList);
        log.info("该员工:{} 今日客户分享:{}", employeeUniqueUuid, todayForwardDto.getClientForwardNum());

        //二度分享
        Query querySecond = new Query();
        Criteria criteriaSecond = new Criteria();
        criteriaSecond.and("corporationCode").is(QfContextHolder.getContext().getCorporationCode());
        criteriaSecond.and("operateType").is(MemberOperateTypeConstants.SHARE.getValue());
        criteriaSecond.and("level").gte(2);
        criteriaSecond.and("employeeUniqueUuid").is(employeeUniqueUuid);
        criteriaSecond.and("createTime").gte(dayZero);
        querySecond.addCriteria(criteriaSecond);
        List<MemberOperate> secondList = mongoTemplate.find(querySecond, MemberOperate.class);
        todayForwardDto.setSecondTimeForwardNum(CollectionUtils.isEmpty(secondList) ? 0 : secondList.size());
        todayForwardDto.setSecondForwardList(secondList);
        log.info("该员工:{} 今日二度分享:{}", employeeUniqueUuid, todayForwardDto.getSecondTimeForwardNum());

        //总转发
        Criteria criteriaTotal = new Criteria();
        criteriaTotal.and("corporationCode").is(QfContextHolder.getContext().getCorporationCode());
        criteriaTotal.and("operateType").is(MemberOperateTypeConstants.SHARE.getValue());
        criteriaTotal.and("employeeUniqueUuid").is(employeeUniqueUuid);
        criteriaTotal.and("createTime").gte(dayZero);
        Query queryTotal = new Query(criteriaTotal);
        List<MemberOperate> totalList = mongoTemplate.find(queryTotal, MemberOperate.class);
        todayForwardDto.setForwardNum(CollectionUtils.isEmpty(totalList) ? 0 : totalList.size());
        todayForwardDto.setTotalForwardList(totalList);
        log.info("该员工:{} 今日总分享:{}", employeeUniqueUuid, todayForwardDto.getForwardNum());

        return todayForwardDto;
    }

    @Override
    public TodayExchangeDto getTodayExchange(String employeeUniqueUuid, String memberId) {

        TodayExchangeDto todayExchangeDto = new TodayExchangeDto();
        //今日时间
        Date dayZero = getDayZero(new Date());
        /**
         * 房源互动
         * 被他人【转发房源】和【浏览房源】的总次数
         */
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("corporationCode").is(QfContextHolder.getContext().getCorporationCode());
        criteria.orOperator(Criteria.where("operateType").is(MemberOperateTypeConstants.EXPLORE.getValue()),
                Criteria.where("operateType").is(MemberOperateTypeConstants.SHARE.getValue()));
        //只限房源相关
        criteria.andOperator(Criteria.where("businessType").ne(BusinessConstants.EMPLOYEE.getCode()),
                Criteria.where("businessType").ne(BusinessConstants.ESTATE.getCode()),
                Criteria.where("businessType").ne(BusinessConstants.MEMBER.getCode()));
        criteria.and("employeeUniqueUuid").is(employeeUniqueUuid);
        criteria.and("memberId").ne(memberId);
        //criteria.and("level").gte(1);
        criteria.and("createTime").gte(dayZero);
        query.addCriteria(criteria);
        long count = mongoTemplate.count(query, MemberOperate.class);
        log.info("该员工:{} 今日房源互动次数:{}", employeeUniqueUuid, count);
        todayExchangeDto.setPropertyExchangeNum((int) count);

        /**
         * 名片互动
         * 被他人【转发名片】和【浏览名片】的总次数
         */
        Query queryCarte = new Query();
        Criteria criteriaCarte = new Criteria();
        criteriaCarte.and("corporationCode").is(QfContextHolder.getContext().getCorporationCode());
        criteriaCarte.orOperator(Criteria.where("operateType").is(MemberOperateTypeConstants.EXPLORE.getValue()),
                Criteria.where("operateType").is(MemberOperateTypeConstants.SHARE.getValue()));
        criteriaCarte.and("businessType").is(BusinessConstants.EMPLOYEE.getCode());
        criteriaCarte.and("employeeUniqueUuid").is(employeeUniqueUuid);
        criteriaCarte.and("memberId").ne(memberId);
        criteriaCarte.and("createTime").gte(dayZero);
        queryCarte.addCriteria(criteriaCarte);
        long countCarte = mongoTemplate.count(queryCarte, MemberOperate.class);
        log.info("该员工:{} 今日名片互动次数:{}", employeeUniqueUuid, countCarte);
        todayExchangeDto.setCarteExchangeTotalNum((int) countCarte);

        /**咨询互动
         * 进行过聊天和拨打过电话总次数
         */
        Criteria criteriaAdvisory = new Criteria();
        criteriaAdvisory.and("corporationCode").is(QfContextHolder.getContext().getCorporationCode());

        criteriaAdvisory.orOperator(
                Criteria.where("operateType").is(MemberOperateTypeConstants.CHAT.getValue()),
                Criteria.where("operateType").is(MemberOperateTypeConstants.CALL.getValue())
        );
        criteriaAdvisory.and("employeeUniqueUuid").is(employeeUniqueUuid);
        criteriaAdvisory.and("createTime").gte(dayZero);
        Query queryAdvisory = new Query(criteriaAdvisory);
        List<MemberOperate> memberOperates = mongoTemplate.find(queryAdvisory, MemberOperate.class);
        todayExchangeDto.setAdvisoryExchangeTotalNum(CollectionUtils.isEmpty(memberOperates) ? 0 : memberOperates.size());
        todayExchangeDto.setAdvisoryExchangeList(memberOperates);
        log.info("该员工:{} 今日咨询互动次数:{}", employeeUniqueUuid, todayExchangeDto.getAdvisoryExchangeTotalNum());

        /**
         * 今日总互动数
         *【转发过经纪人门店或经纪人门店房源】或【与该经纪人进行过聊天】或【拨打过电话】
         */
        todayExchangeDto.setExchangeTotalNum(todayExchangeDto.getPropertyExchangeNum() + todayExchangeDto.getCarteExchangeTotalNum() + todayExchangeDto.getAdvisoryExchangeTotalNum());
        log.info("该员工:{} 今日总互动次数:{}", employeeUniqueUuid, todayExchangeDto.getExchangeTotalNum());
        return todayExchangeDto;
    }

    private Date getDayZero(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }

    /**
     * 数据-今日访问总人数tab
     *
     * @param dailyDataQueryDto
     * @return
     */
    @Override
    public DailyDataForVisitDto getDailyDataForVisit(DailyDataQueryDto dailyDataQueryDto) {

        //今日总访问人数 转粉 关注 互动
        TodayVisitDto todayAllVisit = getTodayVisit(dailyDataQueryDto.getEmployeeUniqueUuid(), dailyDataQueryDto.getMemberId());
        DailyDataForVisitDto dataForVisitDto = memberOperateMapper.TodayVisitDtoToDailyDataForVisitDto(todayAllVisit);
        //访问房源人数
        TodayVisitDataDto visitPropertyNumDaily = getVisitPropertyNumDaily(dailyDataQueryDto);
        dataForVisitDto.setVisitPropertyNum(visitPropertyNumDaily.getVisitTypeNum());
        //访问名片人数
        TodayVisitDataDto visitCarteNumDaily = getVisitCarteNumDaily(dailyDataQueryDto);
        dataForVisitDto.setVisitCarteNum(visitCarteNumDaily.getVisitTypeNum());
        log.info("今日访问数据面板 今日总访问人数：{},访问房源人数:{},访问名片人数:{}", dataForVisitDto.getVisitorsNum(),
                dataForVisitDto.getVisitPropertyNum(), dataForVisitDto.getVisitCarteNum());
        if (StringUtils.equals(dailyDataQueryDto.getType(), DailyDataTypeConstants.VISIT_TOTAL.getDailyDataType())) {
            //如果访客为0 那么互动必为0
            if (dataForVisitDto.getVisitorsNum().equals(0)) {
                dataForVisitDto.setTurnFansNum(0);
            } else {
                //互动人数
                List<String> exchangeMemberIds = todayAllVisit.getExchangeMemberOperateList();
                long count = Optional.ofNullable(todayAllVisit.getVisitMemberOperateList()).orElseGet(Lists::newArrayList)
                        .stream().filter(f -> exchangeMemberIds.contains(f)).count();
                dataForVisitDto.setExchangeNum((int) count);
            }
            log.info("数据-今日访问总人数tab 访问总人数:{},房源人数:{},名片人数:{},转粉人数:{},关注人数:{},互动人数:{}"
                    , dataForVisitDto.getVisitorsNum(), dataForVisitDto.getVisitPropertyNum(), dataForVisitDto.getVisitCarteNum()
                    , dataForVisitDto.getTurnFansNum(), dataForVisitDto.getAttentionNum(), dataForVisitDto.getExchangeNum());
        } else if (StringUtils.equals(dailyDataQueryDto.getType(), DailyDataTypeConstants.VISIT_PROPERTY.getDailyDataType())) {
            //房源人数为标准
            List<String> memberOperateList = visitPropertyNumDaily.getMemberOperateList();
            if (CollectionUtils.isEmpty(memberOperateList)) {
                dataForVisitDto.setTurnFansNum(0);
                dataForVisitDto.setAttentionNum(0);
                dataForVisitDto.setExchangeNum(0);
            } else {
                //今日总转粉
                List<String> fansList = Optional.ofNullable(todayAllVisit.getFansMemberOperateList()).orElseGet(Lists::newArrayList)
                        .stream().map(MemberFocus::getMemberId).collect(Collectors.toList());
                long fansCount = memberOperateList.stream().filter(f -> fansList.contains(f)).count();
                dataForVisitDto.setTurnFansNum((int) fansCount);

                //今日总关注
                List<String> attentionList = Optional.ofNullable(todayAllVisit.getAttentionMemberOperateList()).orElseGet(Lists::newArrayList)
                        .stream().map(MemberFocus::getBusinessUuid).collect(Collectors.toList());
                long attentionCount = memberOperateList.stream().filter(f -> attentionList.contains(f)).count();
                dataForVisitDto.setAttentionNum((int) attentionCount);
                //今日总互动
                List<String> exchangeList = todayAllVisit.getExchangeMemberOperateList();
                long exchangeCount = memberOperateList.stream().filter(f -> exchangeList.contains(f)).count();
                dataForVisitDto.setExchangeNum((int) exchangeCount);
                log.info("数据-访问房源人数tab 访问总人数:{},房源人数:{},名片人数:{},转粉人数:{},关注人数:{},互动人数:{}"
                        , dataForVisitDto.getVisitorsNum(), dataForVisitDto.getVisitPropertyNum(), dataForVisitDto.getVisitCarteNum()
                        , dataForVisitDto.getTurnFansNum(), dataForVisitDto.getAttentionNum(), dataForVisitDto.getExchangeNum());
            }
        } else if (StringUtils.equals(dailyDataQueryDto.getType(), DailyDataTypeConstants.VISIT_CARTE.getDailyDataType())) {
            //访问名片人数为标准
            List<String> memberOperateList = visitCarteNumDaily.getMemberOperateList();
            if (CollectionUtils.isEmpty(memberOperateList)) {
                dataForVisitDto.setTurnFansNum(0);
                dataForVisitDto.setAttentionNum(0);
                dataForVisitDto.setExchangeNum(0);
            } else {
                //今日总转粉
                List<String> fansList = Optional.ofNullable(todayAllVisit.getFansMemberOperateList()).orElseGet(Lists::newArrayList)
                        .stream().map(MemberFocus::getMemberId).collect(Collectors.toList());
                long fansCount = memberOperateList.stream().filter(f -> fansList.contains(f)).count();
                dataForVisitDto.setTurnFansNum((int) fansCount);

                //今日总关注
                List<String> attentionList = Optional.ofNullable(todayAllVisit.getAttentionMemberOperateList()).orElseGet(Lists::newArrayList)
                        .stream().map(MemberFocus::getBusinessUuid).collect(Collectors.toList());
                long attentionCount = memberOperateList.stream().filter(f -> attentionList.contains(f)).count();
                dataForVisitDto.setAttentionNum((int) attentionCount);
                //今日总互动
                List<String> exchangeList = todayAllVisit.getExchangeMemberOperateList();
                long exchangeCount = memberOperateList.stream().filter(f -> exchangeList.contains(f)).count();
                dataForVisitDto.setExchangeNum((int) exchangeCount);
                log.info("数据-访问名片人数tab 访问总人数:{},房源人数:{},名片人数:{},转粉人数:{},关注人数:{},互动人数:{}"
                        , dataForVisitDto.getVisitorsNum(), dataForVisitDto.getVisitPropertyNum(), dataForVisitDto.getVisitCarteNum()
                        , dataForVisitDto.getTurnFansNum(), dataForVisitDto.getAttentionNum(), dataForVisitDto.getExchangeNum());
            }
        }
        return dataForVisitDto;
    }

    private TodayVisitDataDto getVisitPropertyNumDaily(DailyDataQueryDto dailyDataQueryDto) {

        //今日总访问人数 要以memberid分组
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("corporationCode").is(QfContextHolder.getContext().getCorporationCode());
        criteria.and("operateType").is(MemberOperateTypeConstants.EXPLORE.getValue());
        criteria.and("businessType").ne(BusinessConstants.EMPLOYEE.getCode());
        criteria.and("employeeUniqueUuid").is(dailyDataQueryDto.getEmployeeUniqueUuid());
        criteria.and("memberId").ne(dailyDataQueryDto.getMemberId());
        criteria.and("createTime").gte(getDayZero(new Date()));
        query.addCriteria(criteria);
        List<String> visitList = mongoTemplate.findDistinct(query, "memberId", MemberOperate.class, String.class);
        log.info("该员工：{},今日访问房源总人数：{}", dailyDataQueryDto.getEmployeeUniqueUuid(), visitList.size());

        TodayVisitDataDto todayVisitDataDto = TodayVisitDataDto.builder()
                .visitTypeNum(CollectionUtils.isEmpty(visitList) ? 0 : visitList.size())
                .memberOperateList(visitList)
                .build();
        return todayVisitDataDto;
    }

    private TodayVisitDataDto getVisitCarteNumDaily(DailyDataQueryDto dailyDataQueryDto) {

        //今日总访问人数 要以memberid分组
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("corporationCode").is(QfContextHolder.getContext().getCorporationCode());
        criteria.and("operateType").is(MemberOperateTypeConstants.EXPLORE.getValue());
        criteria.and("businessType").is(BusinessConstants.EMPLOYEE.getCode());
        criteria.and("employeeUniqueUuid").is(dailyDataQueryDto.getEmployeeUniqueUuid());
        criteria.and("memberId").ne(dailyDataQueryDto.getMemberId());
        criteria.and("createTime").gte(getDayZero(new Date()));
        query.addCriteria(criteria);
        List<String> visitList = mongoTemplate.findDistinct(query, "memberId", MemberOperate.class, String.class);
        log.info("该员工：{},今日访问房源总人数：{}", dailyDataQueryDto.getEmployeeUniqueUuid(), visitList.size());
        TodayVisitDataDto todayVisitDataDto = TodayVisitDataDto.builder()
                .visitTypeNum(CollectionUtils.isEmpty(visitList) ? 0 : visitList.size())
                .memberOperateList(visitList)
                .build();
        return todayVisitDataDto;
    }

    @Override
    public DailyDataForForwardDto getDailyDataForForward(DailyDataQueryDto dailyDataQueryDto) {

        //今日总转发数据面板
        TodayForwardDto todayForward = getTodayForward(dailyDataQueryDto.getEmployeeUniqueUuid(), dailyDataQueryDto.getMemberId());
        DailyDataForForwardDto dailyDataForForwardDto = memberOperateMapper.TodayForwardDtoToDailyDataForForwardDto(todayForward);

        //转发房源次数
        TodayForwardDataDto forwardPropertyNumDaily = getForwardPropertyNumDaily(dailyDataQueryDto);
        dailyDataForForwardDto.setForwardPropertyNum(forwardPropertyNumDaily.getForwardTypeNum());

        //转发名片次数
        TodayForwardDataDto cartePropertyNumDaily = getCartePropertyNumDaily(dailyDataQueryDto);
        dailyDataForForwardDto.setForwardCarteNum(cartePropertyNumDaily.getForwardTypeNum());

        log.info("今日转发数据面板 今日总转发发人数：{},转发房源人数:{},转发名片人数:{}", dailyDataForForwardDto.getForwardNum(),
                dailyDataForForwardDto.getForwardPropertyNum(), dailyDataForForwardDto.getForwardCarteNum());

        /**默认今日总转发面板转发总人数*/
        log.info("数据-今日总转发数tab 今日总转发数:{},转发房源数:{},转发名片数:{},我分享数:{},客户分享数:{},二度分享数:{}"
                , dailyDataForForwardDto.getForwardNum(), dailyDataForForwardDto.getForwardPropertyNum(), dailyDataForForwardDto.getForwardCarteNum()
                , dailyDataForForwardDto.getMineForwardNum(), dailyDataForForwardDto.getClientForwardNum(), dailyDataForForwardDto.getSecondTimeForwardNum());
        if (StringUtils.equals(dailyDataQueryDto.getType(), DailyDataTypeConstants.FORWARD_PROPERTY.getDailyDataType())) {
            //转发房源为数据基础
            List<MemberOperate> memberOperateList = forwardPropertyNumDaily.getMemberOperateList();
            //标准为空就其他都是0
            if (CollectionUtils.isEmpty(memberOperateList)) {
                dailyDataForForwardDto.setMineForwardNum(0);
                dailyDataForForwardDto.setClientForwardNum(0);
                dailyDataForForwardDto.setSecondTimeForwardNum(0);
            } else {
                //基于房源  我转发的次数
                List<String> mineList = Optional.ofNullable(todayForward.getMineForwardList()).orElseGet(Lists::newArrayList)
                        .stream().map(MemberOperate::getMemberId).collect(Collectors.toList());
                long mineCount = memberOperateList.stream().filter(f -> mineList.contains(f.getMemberId())).count();
                dailyDataForForwardDto.setMineForwardNum((int) mineCount);

                //基于房源  客户转发的次数
                List<String> clientList = Optional.ofNullable(todayForward.getClientForwardList()).orElseGet(Lists::newArrayList)
                        .stream().map(MemberOperate::getMemberId).collect(Collectors.toList());
                long clientCount = memberOperateList.stream().filter(f -> clientList.contains(f.getMemberId())).count();
                dailyDataForForwardDto.setClientForwardNum((int) clientCount);

                //基于房源  二度转发的次数
                List<String> secondList = Optional.ofNullable(todayForward.getSecondForwardList()).orElseGet(Lists::newArrayList)
                        .stream().map(MemberOperate::getMemberId).collect(Collectors.toList());
                long secondCount = memberOperateList.stream().filter(f -> secondList.contains(f.getMemberId()) && f.getLevel() > 1).count();
                dailyDataForForwardDto.setSecondTimeForwardNum((int) secondCount);
            }
            log.info("数据-今日转发房源数tab 今日总转发数:{},转发房源数:{},转发名片数:{},我分享数:{},客户分享数:{},二度分享数:{}"
                    , dailyDataForForwardDto.getForwardNum(), dailyDataForForwardDto.getForwardPropertyNum(), dailyDataForForwardDto.getForwardCarteNum()
                    , dailyDataForForwardDto.getMineForwardNum(), dailyDataForForwardDto.getClientForwardNum(), dailyDataForForwardDto.getSecondTimeForwardNum());
        } else if (StringUtils.equals(dailyDataQueryDto.getType(), DailyDataTypeConstants.FORWARD_CARTE.getDailyDataType())) {
            List<MemberOperate> memberOperateList = cartePropertyNumDaily.getMemberOperateList();
            //标准为空就其他都是0
            if (CollectionUtils.isEmpty(memberOperateList)) {
                dailyDataForForwardDto.setMineForwardNum(0);
                dailyDataForForwardDto.setClientForwardNum(0);
                dailyDataForForwardDto.setSecondTimeForwardNum(0);
            } else {
                //基于名片  我转发的次数
                List<String> mineList = Optional.ofNullable(todayForward.getMineForwardList()).orElseGet(Lists::newArrayList)
                        .stream().map(MemberOperate::getMemberId).collect(Collectors.toList());
                long mineCount = memberOperateList.stream().filter(f -> mineList.contains(f.getMemberId())).count();
                dailyDataForForwardDto.setMineForwardNum((int) mineCount);

                //基于名片  客户转发的次数
                List<String> clientList = Optional.ofNullable(todayForward.getClientForwardList()).orElseGet(Lists::newArrayList)
                        .stream().map(MemberOperate::getMemberId).collect(Collectors.toList());
                long clientCount = memberOperateList.stream().filter(f -> clientList.contains(f.getMemberId())).count();
                dailyDataForForwardDto.setClientForwardNum((int) clientCount);

                //基于名片  二度转发的次数
                List<String> secondList = Optional.ofNullable(todayForward.getSecondForwardList()).orElseGet(Lists::newArrayList)
                        .stream().map(MemberOperate::getMemberId).collect(Collectors.toList());
                long secondCount = memberOperateList.stream().filter(f -> secondList.contains(f.getMemberId()) && f.getLevel() > 1).count();
                dailyDataForForwardDto.setSecondTimeForwardNum((int) secondCount);

            }
            log.info("数据-今日转发名片数tab 今日总转发数:{},转发房源数:{},转发名片数:{},我分享数:{},客户分享数:{},二度分享数:{}"
                    , dailyDataForForwardDto.getForwardNum(), dailyDataForForwardDto.getForwardPropertyNum(), dailyDataForForwardDto.getForwardCarteNum()
                    , dailyDataForForwardDto.getMineForwardNum(), dailyDataForForwardDto.getClientForwardNum(), dailyDataForForwardDto.getSecondTimeForwardNum());
        }
        return dailyDataForForwardDto;
    }

    private TodayForwardDataDto getForwardPropertyNumDaily(DailyDataQueryDto dailyDataQueryDto) {
        //今日转发房源次数，不需要memberid分组
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("corporationCode").is(QfContextHolder.getContext().getCorporationCode());
        criteria.and("operateType").is(MemberOperateTypeConstants.SHARE.getValue());
        criteria.and("businessType").ne(BusinessConstants.EMPLOYEE.getCode());
        criteria.and("employeeUniqueUuid").is(dailyDataQueryDto.getEmployeeUniqueUuid());
        criteria.and("createTime").gte(getDayZero(new Date()));
        query.addCriteria(criteria);
        List<MemberOperate> memberOperates = mongoTemplate.find(query, MemberOperate.class);
        log.info("该员工：{},今日转发房源总人数：{}", dailyDataQueryDto.getEmployeeUniqueUuid(), memberOperates.size());
        TodayForwardDataDto todayForwardDataDto = TodayForwardDataDto.builder()
                .forwardTypeNum(CollectionUtils.isEmpty(memberOperates) ? 0 : memberOperates.size())
                .memberOperateList(memberOperates)
                .build();
        return todayForwardDataDto;
    }

    private TodayForwardDataDto getCartePropertyNumDaily(DailyDataQueryDto dailyDataQueryDto) {
        //今日转发名片次数，不需要memberid分组
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("corporationCode").is(QfContextHolder.getContext().getCorporationCode());
        criteria.and("operateType").is(MemberOperateTypeConstants.SHARE.getValue());
        criteria.and("businessType").is(BusinessConstants.EMPLOYEE.getCode());
        criteria.and("employeeUniqueUuid").is(dailyDataQueryDto.getEmployeeUniqueUuid());
        criteria.and("createTime").gte(getDayZero(new Date()));
        query.addCriteria(criteria);
        List<MemberOperate> memberOperates = mongoTemplate.find(query, MemberOperate.class);
        log.info("该员工：{},今日转发名片总人数：{}", dailyDataQueryDto.getEmployeeUniqueUuid(), memberOperates.size());
        TodayForwardDataDto todayForwardDataDto = TodayForwardDataDto.builder()
                .forwardTypeNum(CollectionUtils.isEmpty(memberOperates) ? 0 : memberOperates.size())
                .memberOperateList(memberOperates)
                .build();
        return todayForwardDataDto;
    }

    @Override
    public DailyDataForExchangeDto getDailyDataForExchange(DailyDataQueryDto dailyDataQueryDto) {
        //今日总互动数 转发经纪人门店、经纪人房源】+【与该经纪人进行过聊天】+【拨打过电话】次数总和
        TodayExchangeDto todayExchange = getTodayExchange(dailyDataQueryDto.getEmployeeUniqueUuid(), dailyDataQueryDto.getMemberId());
        DailyDataForExchangeDto dailyDataForExchangeDto = memberOperateMapper.TodayExchangeDtoToDailyDataForExchangeDto(todayExchange);
        //电话 咨询
        List<MemberOperate> advisoryExchangeList = todayExchange.getAdvisoryExchangeList();
        if (CollectionUtils.isEmpty(advisoryExchangeList)) {
            dailyDataForExchangeDto.setCallAdvisoryNum(0);
            dailyDataForExchangeDto.setOnlineAdvisoryNum(0);
        } else {
            long count = todayExchange.getAdvisoryExchangeList().stream().filter(f -> f.getOperateType().equals(MemberOperateTypeConstants.CHAT.getValue())).count();
            dailyDataForExchangeDto.setOnlineAdvisoryNum((int) count);
            dailyDataForExchangeDto.setCallAdvisoryNum(advisoryExchangeList.size() - dailyDataForExchangeDto.getOnlineAdvisoryNum());
        }
        log.info("数据-今日互动数据tab 今日总互动数:{},房源互动数:{},名片互动数:{},线上咨询:{},电话咨询:{}"
                , dailyDataForExchangeDto.getExchangeTotalNum(), dailyDataForExchangeDto.getPropertyExchangeNum(), dailyDataForExchangeDto.getCarteExchangeTotalNum()
                , dailyDataForExchangeDto.getOnlineAdvisoryNum(), dailyDataForExchangeDto.getCallAdvisoryNum());
        return dailyDataForExchangeDto;
    }

    @Override
    public Page<MemberBrowseTracksDto> getMemberBrowseTracks(DailyDataQueryDto dailyDataQueryDto, Pageable pageable) {

        String corporationCode = QfContextHolder.getContext().getCorporationCode();
        Criteria criteria = Criteria.where("memberId").is(dailyDataQueryDto.getMemberId())
                .and("employeeUniqueUuid").is(dailyDataQueryDto.getEmployeeUniqueUuid())
                .and("corporationCode").is(corporationCode);
        Query query = new Query(criteria);
        query.with(Sort.by(Sort.Order.desc("createTime")));

        List<MemberBrowseTracksDto> memberBrowseTracksDtos = new ArrayList<>();
        long count = mongoTemplate.count(query, MemberOperate.class);
        if (count > 0) {
            List<MemberOperate> memberOperates = mongoTemplate.find(query.with(pageable), MemberOperate.class);
            //房源相关（浏览、转发）  Map<Integer, List<MemberOperate>> propertyOperateMap =
            Map<Integer, List<MemberOperate>> propertyOperateMap = memberOperates.stream().filter(f -> (MemberOperateTypeConstants.EXPLORE.getValue().equals(f.getOperateType())
                    || MemberOperateTypeConstants.SHARE.getValue().equals(f.getOperateType())))
                    .filter(f -> !BusinessConstants.EMPLOYEE.getCode().equals(f.getBusinessType()))
                    .collect(Collectors.groupingBy(MemberOperate::getBusinessType));

            List<String> firstPropertyList = new ArrayList<>();
            List<String> saleAndRentPropertyList = new ArrayList<>();
            for (Integer businessType : propertyOperateMap.keySet()) {
                //新房
                if (BusinessConstants.FIRSTHAND_ESTATE.getCode().equals(businessType)) {
                    List<String> collect = Optional.ofNullable(propertyOperateMap.get(businessType)).orElseGet(Lists::newArrayList)
                            .stream().map(MemberOperate::getBusinessUuid).collect(Collectors.toList());
                    firstPropertyList.addAll(collect);
                } else {
                    List<String> collect = Optional.ofNullable(propertyOperateMap.get(businessType)).orElseGet(Lists::newArrayList)
                            .stream().map(MemberOperate::getBusinessUuid).collect(Collectors.toList());
                    saleAndRentPropertyList.addAll(collect);
                }
            }

            //查询新房详情
            List<FirsthandEstateListDto> firsthandEstateListDtoList = new ArrayList<>();
            if (!CollectionUtils.isEmpty(firstPropertyList)) {
                FirsthandEstateQueryDto firsthandEstateQueryDto = new FirsthandEstateQueryDto();
                firsthandEstateQueryDto.setCorporationCode(corporationCode);
                firsthandEstateQueryDto.setEstateUniqueUuids(firstPropertyList);
                List<FirsthandEstate> firsthandEstateList = firsthandEstateService.findAllByParams(firsthandEstateQueryDto);
                firsthandEstateListDtoList = firsthandEstateList.stream().map(firsthandEstateMapper::domainToListDto).collect(Collectors.toList());
            }
            log.info("member BrowseTracks firsthandList:{}", JSONObject.toJSONString(firsthandEstateListDtoList));
            //查询二手出租详情
            List<MyPropertyListDto> propertyListDtoList = new ArrayList<>();
            if (!CollectionUtils.isEmpty(saleAndRentPropertyList)) {
                List<Property> propertyList = propertyRepository.findAllByCorporationCodeAndPropertyUniqueUuidIn(corporationCode, saleAndRentPropertyList);
                propertyListDtoList = propertyList.stream().map(propertyMapper::domainToMyHouseListDto).collect(Collectors.toList());
            }
            log.info("member BrowseTracks propertyList:{}", JSONObject.toJSONString(propertyListDtoList));
            Map<String, FirsthandEstateListDto> firsthandDtoMap = firsthandEstateListDtoList.stream().collect(Collectors.toMap(FirsthandEstateListDto::getEstateUniqueUuid, a -> a, (k1, k2) -> k1));
            Map<String, MyPropertyListDto> propertyDtoMap = propertyListDtoList.stream().collect(Collectors.toMap(MyPropertyListDto::getPropertyUniqueUuid, a -> a, (k1, k2) -> k1));
            Long startTime = System.currentTimeMillis();
            memberBrowseTracksDtos = memberOperates.stream().map(memberOperate -> {
                MemberBrowseTracksDto memberBrowseTracksDto = converData(memberOperate, firsthandDtoMap, propertyDtoMap);
                return memberBrowseTracksDto;
            }).collect(Collectors.toList());
            log.info("组装会员浏览轨迹耗时:{} ms, 数据大小:{}", System.currentTimeMillis() - startTime, memberOperates.size());
        }
        return PageableExecutionUtils.getPage(memberBrowseTracksDtos, pageable, () -> count);
    }

    /**
     * 组装数据
     *
     * @param memberOperate
     * @return
     */
    private MemberBrowseTracksDto converData(MemberOperate memberOperate, Map<String, FirsthandEstateListDto> firsthandDtoMap, Map<String, MyPropertyListDto> propertyDtoMap) {

        MemberBrowseTracksDto memberBrowseTracksDto = new MemberBrowseTracksDto();
        memberBrowseTracksDto.setPropertyType(memberOperate.getBusinessType());
        //浏览需要拼接浏览时长,没有结束时间就不计算了
        String duration = "";
        if (MemberOperateTypeConstants.EXPLORE.getValue().equals(memberOperate.getOperateType()) && memberOperate.getEndTime() != null) {
            long time = DateUtil.between(memberOperate.getCreateTime(), memberOperate.getEndTime(), DateUnit.SECOND, false);
            if (time <= 60 && time > 0) {
                duration = time + "秒";
            } else if (time > 60) {
                time = DateUtil.between(memberOperate.getCreateTime(), memberOperate.getEndTime(), DateUnit.MINUTE, false);
                duration = time + "分钟";
            }
        }
        memberBrowseTracksDto.setDuration(duration);
        //动作类型
        String browseType;
        switch (memberOperate.getOperateType()) {
            case 1:
                browseType = BusinessConstants.EMPLOYEE.getCode().equals(memberOperate.getBusinessType()) ? "浏览名片" : "浏览房源";
                break;
            case 2:
                browseType = BusinessConstants.EMPLOYEE.getCode().equals(memberOperate.getBusinessType()) ? "转发名片" : "转发房源";
                break;
            case 3:
                browseType = MemberOperateTypeConstants.CHAT.getName();
                break;
            case 4:
                browseType = MemberOperateTypeConstants.CALL.getName();
                break;
            default:
                throw new IllegalStateException("Unexpected value: " + memberOperate.getOperateType());
        }
        memberBrowseTracksDto.setBrowseType(browseType);

        //房源相关
        if (BusinessConstants.FIRSTHAND_ESTATE.getCode().equals(memberOperate.getBusinessType()) && !CollectionUtils.isEmpty(firsthandDtoMap)) {
            memberBrowseTracksDto.setFirsthandEstate(firsthandDtoMap.get(memberOperate.getBusinessUuid()));
            memberBrowseTracksDto.setPropertyId(memberOperate.getBusinessUuid());

        } else if ((BusinessConstants.SALE_PROPERTY.getCode().equals(memberOperate.getBusinessType())
                || BusinessConstants.RENT_PROPERTY.getCode().equals(memberOperate.getBusinessType()))
                && !CollectionUtils.isEmpty(propertyDtoMap)) {
            memberBrowseTracksDto.setPropertyData(propertyDtoMap.get(memberOperate.getBusinessUuid()));
            memberBrowseTracksDto.setPropertyId(memberOperate.getBusinessUuid());
        }
        memberBrowseTracksDto.setCreateTime(dateTransform(memberOperate.getCreateTime()));
        return memberBrowseTracksDto;
    }

    private String dateTransform(Date date) {
        if (date == null) {
            return "";
        }
        //年度判断
        String time;
        if (DateUtil.thisYear() == DateUtil.year(date)) {
            //今天
            if (DateUtil.isSameDay(new Date(), date)) {
                time = DateUtil.format(date, "HH:mm");
            } else {
                long l = DateUtil.betweenDay(date, new Date(), true);
                time = l == 1L ? "昨天" + " " + DateUtil.format(date, "HH:mm") : DateUtil.format(date, "MM/dd HH:mm");
            }
            return time;
        }
        return DateUtil.format(date, "yyyy/MM/dd");
    }

    @Override
    public String updateMemberRemark(UpdateMemberRemarkDto dto) {
        Employee employee = employeeRepository.findByEmployeeUniqueUuid(dto.getEmployeeUniqueUuid());
        if (employee == null) {
            throw new BusinessException("经纪人信息不存在");
        }
        log.info("updateMemberRemark employee:{},member:{}", JSONObject.toJSONString(employee));
        List<MemberRemark> remarkList = employee.getRemarkList();

        if (CollectionUtils.isEmpty(remarkList)) {
            remarkList = new ArrayList<>();
        } else {
            Iterator<MemberRemark> iterator = remarkList.iterator();
            while (iterator.hasNext()) {
                MemberRemark memberRemark = iterator.next();
                if (StringUtils.equals(dto.getMemberId(), memberRemark.getMemberId())) {
                    iterator.remove();
                    break;
                }
            }
        }
        String remark;
        //设置备注
        if (StringUtils.isNotEmpty(dto.getRemark())) {
            MemberRemark memberRemark = new MemberRemark();
            BeanUtils.copyProperties(dto, memberRemark);
            remarkList.add(memberRemark);
            remark = dto.getRemark();
        } else {
            Member member = memberRepository.findByCorporationCodeAndId(QfContextHolder.getContext().getCorporationCode(), dto.getMemberId());
            if (member == null) {
                throw new BusinessException("该会员信息不存在");
            }
            remark = member.getName();
        }
        Query query = new Query(Criteria.where("employeeUniqueUuid").is(dto.getEmployeeUniqueUuid()));
        Update update = new Update().set("remarkList", remarkList);
        mongoTemplate.update(Employee.class)
                .matching(query)
                .apply(update)
                .withOptions(FindAndModifyOptions.options().returnNew(true))
                .findAndModifyValue();
        return remark;
    }

    @Override
    public List<MemberShareTracksDto> getMemberShareTrack(DailyDataQueryDto dailyDataQueryDto) {
        String corporationCode = QfContextHolder.getContext().getCorporationCode();
        Criteria criteria = new Criteria();
        criteria.and("corporationCode").is(corporationCode);
        criteria.and("employeeUniqueUuid").is(dailyDataQueryDto.getEmployeeUniqueUuid());
        criteria.and("memberId").is(dailyDataQueryDto.getMemberId());
        criteria.and("linkedUuid").exists(true);
        Query query = new Query(criteria);
        query.with(Sort.by(Sort.Order.asc("createTime")));
        List<MemberOperate> memberOperateList = mongoTemplate.find(query, MemberOperate.class);
        List<MemberShareTracksDto> memberShareTracksDtoList = new ArrayList<>();
        if (CollectionUtils.isEmpty(memberOperateList)) {
            return memberShareTracksDtoList;
        }
        //会员和经纪人最初的来源关系图-链路uuid
        String linkedUuid = memberOperateList.get(0).getLinkedUuid();
        //经纪人会员信息
        Member member = memberRepository.findFirstByCorporationCodeAndEmployeeUniqueUuid(corporationCode, dailyDataQueryDto.getEmployeeUniqueUuid());
        if (member == null) {
            log.info("该经纪人在小程序中暂未注册登录,查询不到记录");
        }
        Employee employee = employeeRepository.findByEmployeeUniqueUuid(dailyDataQueryDto.getEmployeeUniqueUuid());
        Query queryLinked = new Query(Criteria.where("linkedUuid").is(linkedUuid));
        queryLinked.with(Sort.by(Sort.Order.desc("operateType")));
        List<MemberOperate> operateList = mongoTemplate.find(queryLinked, MemberOperate.class);

        //根据memberId去重
        Iterator<MemberOperate> iterator = operateList.iterator();
        Set<String> memberIds = new HashSet<>();
        while (iterator.hasNext()) {
            MemberOperate operate = iterator.next();
            if (memberIds.contains(operate.getMemberId())) {
                iterator.remove();
                continue;
            }
            memberIds.add(operate.getMemberId());
        }

        //根据level排序
        Collections.sort(operateList, new Comparator<MemberOperate>() {
            @Override
            public int compare(MemberOperate o1, MemberOperate o2) {
                int i = o1.getLevel() - o2.getLevel();
                if (i == 0) {
                    i = (int) (o1.getCreateTime().getTime() - o2.getCreateTime().getTime());
                }
                return i;
            }
        });


        memberShareTracksDtoList = Optional.ofNullable(operateList).orElseGet(Lists::newArrayList)
                .stream().map(memberOperateMapper::domainToShareTracksDto).map(item -> {
                    if (StringUtils.equals(dailyDataQueryDto.getMemberId(), item.getMemberId())) {
                        item.setIdentity(Boolean.TRUE);
                    } else if (member != null && (StringUtils.equals(member.getId(), item.getMemberId()))) {
                        item.setMemberName("我");
                    }
                    return item;
                }).collect(Collectors.toList());

        //循环遍历经纪人对客户的备注展示
        if (employee != null && !CollectionUtils.isEmpty(employee.getRemarkList())) {
            Map<String, String> remarkMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(employee.getRemarkList())) {
                remarkMap = employee.getRemarkList().stream().collect(Collectors.toMap(MemberRemark::getMemberId, MemberRemark::getRemark, (k1, k2) -> k1));
            }
            for (MemberShareTracksDto memberShareTracksDto : memberShareTracksDtoList) {
                String remark = remarkMap.get(memberShareTracksDto.getMemberId());
                if (StringUtils.isNotEmpty(remark)) {
                    memberShareTracksDto.setMemberName(remark);
                }
            }
        }
        return memberShareTracksDtoList;
    }

    @Override
    public Page<CustomerManageDto> getVisitorList(String employeeUniqueUuid, Pageable pageable) {
        String corporationCode = QfContextHolder.getContext().getCorporationCode();
        Criteria criteria = new Criteria().and("corporationCode").is(corporationCode)
                .and("employeeUniqueUuid").is(employeeUniqueUuid)
                .and("operateType").is(MemberOperateTypeConstants.EXPLORE.getValue());
        Member member = memberRepository.findFirstByCorporationCodeAndEmployeeUniqueUuid(corporationCode, employeeUniqueUuid);
        Criteria criteriaFocus = Criteria.where("businessType").is("会员")
                .and("memberId").is(member.getId());
        Query query = new Query(criteriaFocus);
        //过滤已关注会员
        if (mongoTemplate.count(query, MemberFocus.class) > 0) {
            List<MemberFocus> list = mongoTemplate.find(query, MemberFocus.class);
            List<String> memberIdList = Optional.ofNullable(list).orElseGet(Lists::newArrayList).stream().map(MemberFocus::getBusinessUuid).distinct().collect(Collectors.toList());
            criteria.and("memberId").nin(memberIdList);
        }
        Aggregation aggCount = Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.group("memberId").first("memberId").as("memberId")
        );
        AggregationResults countResult = mongoTemplate.aggregate(aggCount, "member_member_operate", VisitorRecordsSimpleDto.class);
        int count = countResult.getMappedResults().size();
        List<CustomerManageDto> customerManageDtoList = new ArrayList<>();
        if (count > 0) {
            Aggregation agg = Aggregation.newAggregation(
                    Aggregation.match(criteria),
                    Aggregation.sort(DESC, "createTime"),//分组前排序
                    Aggregation.group("memberId").first("memberId").as("memberId")
                            .first("createTime").as("createTime"),
                    Aggregation.sort(DESC, "createTime", "memberId"),//分组后排序
                    Aggregation.skip(pageable.getOffset()),
                    Aggregation.limit(pageable.getPageSize())
            );
            AggregationResults result = mongoTemplate.aggregate(agg, "member_member_operate", VisitorRecordsSimpleDto.class);
            //所有访客
            List<VisitorRecordsSimpleDto> visitorRecordsListDtos = result.getMappedResults();
            List<String> memberIdList = Optional.ofNullable(visitorRecordsListDtos).orElseGet(Lists::newArrayList).stream().map(VisitorRecordsSimpleDto::getMemberId).distinct().collect(Collectors.toList());
            //只展示未被经纪人关注的访客
            customerManageDtoList = memberExploreService.assembleCustomerParams(memberIdList, employeeUniqueUuid);
        }
        return PageableExecutionUtils.getPage(customerManageDtoList, pageable, () -> count);
    }

    @Override
    public Page<CustomerManageDto> getFansList(String employeeUniqueUuid, Pageable pageable) {
        String corporationCode = QfContextHolder.getContext().getCorporationCode();
        Criteria criteria = Criteria.where("businessType").is("经纪人")
                .and("businessUuid").is(employeeUniqueUuid)
                .and("corporationCode").is(corporationCode);
        Query query = new Query(criteria);
        query.with(Sort.by(DESC, "createTime"));
        query.with(pageable);
        List<CustomerManageDto> customerManageDtoList = new ArrayList<>();
        long count = mongoTemplate.count(query, MemberFocus.class);
        if (count > 0) {
            List<MemberFocus> list = mongoTemplate.find(query, MemberFocus.class);
            List<String> memberIdList = Optional.ofNullable(list).orElseGet(Lists::newArrayList).stream().map(MemberFocus::getMemberId).distinct().collect(Collectors.toList());
            customerManageDtoList = memberExploreService.assembleCustomerParams(memberIdList, employeeUniqueUuid);
        }
        return PageableExecutionUtils.getPage(customerManageDtoList, pageable, () -> count);
    }

    @Override
    public Page<CustomerManageDto> getFocusList(String employeeUniqueUuid, Pageable pageable) {
        String corporationCode = QfContextHolder.getContext().getCorporationCode();
        Member member = memberRepository.findFirstByCorporationCodeAndEmployeeUniqueUuid(corporationCode, employeeUniqueUuid);
        if (member == null) {
            throw new BusinessException("经纪人未注册小程序");
        }
        Criteria criteria = Criteria.where("businessType").is("会员")
                .and("memberId").is(member.getId())
                .and("corporationCode").is(corporationCode);
        Query query = new Query(criteria);
        query.with(Sort.by(DESC, "createTime"));
        query.with(pageable);
        List<CustomerManageDto> customerManageDtoList = new ArrayList<>();
        long count = mongoTemplate.count(query, MemberFocus.class);
        if (count > 0) {
            List<MemberFocus> list = mongoTemplate.find(query, MemberFocus.class);
            List<String> memberIdList = Optional.ofNullable(list).orElseGet(Lists::newArrayList).stream().map(MemberFocus::getBusinessUuid).distinct().collect(Collectors.toList());
            customerManageDtoList = memberExploreService.assembleCustomerParams(memberIdList, employeeUniqueUuid);
        }
        return PageableExecutionUtils.getPage(customerManageDtoList, pageable, () -> count);
    }

    @Override
    public CustomerManageDto getEmpMemberDetail(EmpMemberDetailDto empMemberDetailDto) {
        String strArr[] = {empMemberDetailDto.getMemberId()};
        return memberExploreService.assembleCustomerParams(Arrays.asList(strArr), empMemberDetailDto.getEmployeeUniqueUuid()).get(0);
    }

    @Override
    public Map<String, List<MemberOperateSimpleDto>> getOperateReportData(Date date, String corporationCode) {
        Map<String, List<MemberOperateSimpleDto>> map = new HashMap<>();
        Criteria criteria = Criteria.where("corporationCode").is(corporationCode)
                .and("createTime").gte(DateTypeUtil.getDayZero(date)).lt(DateTypeUtil.getDayZero(DateTypeUtil.getTomorrow(date)));
        Aggregation agg = Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.group("employeeUniqueUuid", "memberId", "operateType", "businessType", "shareTo")
                        .first("employeeUniqueUuid").as("employeeUniqueUuid")
                        .first("memberId").as("memberId")
                        .first("operateType").as("operateType")
                        .first("businessType").as("businessType")
                        .first("shareTo").as("shareTo")
                        .count().as("count")
        );
        AggregationResults result = mongoTemplate.aggregate(agg, "member_member_operate", MemberOperateSimpleDto.class);
        List<MemberOperateSimpleDto> simpleDtoList = result.getMappedResults();
        if (!CollectionUtils.isEmpty(simpleDtoList)){
            for (MemberOperateSimpleDto simpleDto : simpleDtoList) {
                String employeeUniqueUuid = simpleDto.getEmployeeUniqueUuid();
                List<MemberOperateSimpleDto> list = map.get(employeeUniqueUuid);
                if (list == null){
                    list = new LinkedList<>();
                }
                list.add(simpleDto);
                map.put(employeeUniqueUuid, list);
            }
        }
        return map;
    }
}






